package router

import (
	"crow-docker/src/service"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/toolkits/pkg/logger"
	"net/http"
)

var upgrader = websocket.Upgrader{
	// 解决跨域问题
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

// GetContainersList 获取虚拟机容器列表
// @Summary 获取虚拟机容器列表
// @Description 获取虚拟机容器列表
// @Tags 容器管理
// @Param ip_addr query string true "客户机id"
// @Param api_port query string true "客户机API端口"
// @Success 200 {object} response.Response{data=[]types.Container} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
// @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
// @Router /api/v1/docker/containers [get]
// @Security Bearer
func GetContainersList(c *gin.Context) {
	ipAddr := c.Query("ip_addr")
	dockerApiPort := c.Query("api_port")

	//链接docker
	dockerCli, err := service.ConnectDocker(ipAddr, dockerApiPort)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	containers, err := service.GetContainers(dockerCli)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	SetOK(c, containers)
}

// GetContainer 查询指定容器
// @Summary 查询指定容器
// @Description 查询指定容器
// @Tags 容器管理
// @Param ip_addr query string true "客户机ip"
// @Param api_port query string true "docker-API端口"
// @Param container_id query string true "容器ID"
// @Success 200 {object} response.Response{data=[]types.Container} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
// @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
// @Router /api/v1/docker/container [get]
// @Security Bearer
func GetContainer(c *gin.Context) {
	ipAddr := c.Query("ip_addr")
	dockerApiPort := c.Query("api_port")
	containerId := c.Query("container_id")
	//链接docker
	dockerCli, err := service.ConnectDocker(ipAddr, dockerApiPort)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	containers, err := service.GetContainer(dockerCli, containerId)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	SetOK(c, containers)
}

// GetContainerLogs 获取指定容器日志
// @Summary 获取指定容器日志
// @Description 获取指定容器日志（websocket接口）
// @Tags 容器管理
// @Param ip_addr query string true "客户机IP"
// @Param api_port query string true "docker-API端口"
// @Param uuid query string true "容器id"
// @Success 200 {object} response.Response{data=string} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
// @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
// @Router /api/v1/docker/container/logs [get]
// @Security Bearer
func GetContainerLogs(c *gin.Context) {
	containerId := c.Query("container_id")
	ipAddr := c.Query("ip_addr")
	dockerApiPort := c.Query("api_port")

	//升级接口
	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)

	if err != nil {
		logger.Info(err)
		return
	}
	defer ws.Close()

	//接收消息的携程
	go func() {
		for {
			_, message, err := ws.ReadMessage()
			if err != nil {
				logger.Error("接口断开:", err)
				ws.Close()
				return
			}
			logger.Info(string(message))
		}
	}()
	//链接docker
	dockerCli, err := service.ConnectDockerForWebsocket(ipAddr, dockerApiPort)
	if err != nil {
		logger.Info(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	//获取日志
	err = service.GetContainerLogs(dockerCli, ws, containerId)
	if err != nil {
		logger.Info(err)
		SetErr(c, 500, err, err.Error())
		return
	}

}

// SendCommendForContainer 终端执行命令
func SendCommendForContainer(c *gin.Context) {
	var sendCommandRequire service.GetCommandResultRequest
	sendCommandRequire.IpAddr = c.Query("ip_addr")
	sendCommandRequire.ContainerUuid = c.Query("container_id")
	sendCommandRequire.ApiPort = c.Query("api_port")

	//升级接口
	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		fmt.Print("升级websocket连接错误:", err)
		return
	}
	defer ws.Close()
	//链接docker
	dockerCli, err := service.ConnectDockerForWebsocket(sendCommandRequire.IpAddr, sendCommandRequire.ApiPort)
	if err != nil {
		SetErr(c, 500, err, err.Error())
		return
	}
	//保持docker链接
	execHr := new(types.HijackedResponse)
	err = service.ExecAttach(dockerCli, execHr, sendCommandRequire.ContainerUuid)

	//接收信息的携程
	go func() {
		for {
			_, message, err := ws.ReadMessage()
			if err != nil {
				logger.Error("接口断开:", err)
				execHr.Close()
				ws.Close()
				return
			}

			logger.Info(string(message))
			//发送命令
			err = service.SendCommend(string(message), execHr)
			if err != nil {
				logger.Error("命令发送错误")
			}
		}
	}()
	//输入命令接收结果
	err = service.ExecContainer(execHr, ws)
	if err != nil {
		SetErr(c, 500, err, err.Error())
		return
	}
	logger.Info("链接关闭")
}

// CreateContainer 创建容器
// @Summary 创建容器
// @Description 创建容器
// @Tags 容器管理
// @Param data body  service.CreateContainerRequest  true "创建容器信息"
// @Success 200 {object} response.Response{data=string} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
// @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
// @Router /api/v1/docker/container [post]
// @Security Bearer
func CreateContainer(c *gin.Context) {
	var createContainerRequest service.CreateContainerRequest
	err := c.Bind(&createContainerRequest)
	if err != nil {
		SetErr(c, 500, err, err.Error())
		return
	}
	//链接docker
	dockerCli, err := service.ConnectDocker(createContainerRequest.IpAddr, createContainerRequest.ApiPort)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	//解释request到 docker的sdk
	config, hostConfig := service.CreateContainerRequest2DockerUse(createContainerRequest)

	//创建容器
	containerId, err := service.CreateContainer(dockerCli, config, hostConfig, nil, createContainerRequest.ContainerName)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	//启动容器
	err = service.StartContainer(dockerCli, containerId)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	SetOK(c, containerId)
}

// OptionContainer 操作容器
// @Summary 操作容器
// @Description 操作容器（1：启动，2：停止，3：重启）
// @Tags 容器管理
// @Param data body  service.OptionContainerRequest  true "操作信息"
// @Success 200 {object} response.Response{data=string} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
// @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
// @Router /api/v1/docker/container [put]
// @Security Bearer
func OptionContainer(c *gin.Context) {
	var optionContainerRequest service.OptionContainerRequest
	err := c.Bind(&optionContainerRequest)
	if err != nil {
		SetErr(c, 500, err, err.Error())
		return
	}
	//链接docker
	dockerCli, err := service.ConnectDocker(optionContainerRequest.IpAddr, optionContainerRequest.ApiPort)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	//操作
	switch optionContainerRequest.Command {
	case 1:
		fmt.Println("start")
		err = service.StartContainer(dockerCli, optionContainerRequest.ContainerId)
		if err != nil {
			logger.Error(err)
			SetErr(c, 500, err, err.Error())
			return
		}
	case 2:
		fmt.Println("stop")
		err = service.StopContainer(dockerCli, optionContainerRequest.ContainerId)
		if err != nil {
			logger.Error(err)
			SetErr(c, 500, err, err.Error())
			return
		}
	case 3:
		fmt.Println("restart")
		err = service.RestartContainer(dockerCli, optionContainerRequest.ContainerId)
		if err != nil {
			logger.Error(err)
			SetErr(c, 500, err, err.Error())
			return
		}
	}
	SetOK(c, "操作成功")
}

// DeleteContainer 删除容器
// @Summary 删除容器
// @Description 删除容器
// @Tags 容器管理
// @Param data body service.DeleteContainerRequest  true "删除镜像的信息"
// @Success 200 {object} response.Response{data=string} "{"requestId": "string","code": 200,"msg": "ok","data": [...]}"
// @Failure 500 {object} response.Response{msg=string} "{"requestId": "string","code": 500,"msg": "string","status": "error","data": null}"
// @Router /api/v1/docker/container [delete]
// @Security Bearer
func DeleteContainer(c *gin.Context) {
	var deleteContainerRequest service.DeleteContainerRequest
	err := c.Bind(&deleteContainerRequest)
	if err != nil {
		SetErr(c, 500, err, err.Error())
		return
	}
	//链接docker
	dockerCli, err := service.ConnectDocker(deleteContainerRequest.IpAddr, deleteContainerRequest.ApiPort)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	//操作

	err = service.DeleteContainer(dockerCli, deleteContainerRequest.ContainerId)
	if err != nil {
		logger.Error(err)
		SetErr(c, 500, err, err.Error())
		return
	}
	SetOK(c, "操作成功")
}
